﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.MLAgents;

// This is a Singleton class, only be instantiated and appended on the gamoObject "EnvironmentController" in main scene once
public class EnvironmentController : MonoBehaviour
{
    public EnvParaManager epm;
    
    public GameObject playgroundPrefab;
    [HideInInspector] public List<PlaygroundController> plygrndCtrlers;
    [HideInInspector] public CameraController cameraController;
    [HideInInspector] public bool isHardReset; // if some env parameter changed and the env need a hard reset to apply it
    [HideInInspector] public SideChannelController sideChannelController;
    [HideInInspector] private bool isFirstReset;
    public int doneAgentNum;
    public bool isDone; // if the env has done already
    

    //public int uniqueAgentIdPointer;

    void Awake()
    {
        //Be careful to the order of the statements
        sideChannelController = GameObject.Find("SideChannelController").GetComponent<SideChannelController>();
        isHardReset = false;
        isFirstReset = true;
        isDone = false;
        epm = new EnvParaManager();
        cameraController = GameObject.Find("MainCamera").GetComponent<CameraController>();
        plygrndCtrlers = new List<PlaygroundController>();
        Academy.Instance.OnEnvironmentReset += EnvironmentReset;
        Academy.Instance.AutomaticSteppingEnabled = false;
    }

    void Instantiate()
    {
        doneAgentNum = 0;
        plygrndCtrlers.Clear();
        Random.InitState((int)epm.GetPara(EP.seed));
        isDone = false;
        Vector3 plygrndPosPointer = Vector3.zero;
        for(int i=0; i<(int)epm.GetPara(EP.playgroundNumber); i++)
        {
            GameObject plygrnd = GameObject.Instantiate(playgroundPrefab, plygrndPosPointer, Quaternion.Euler(Vector3.zero));
            PlaygroundController pgc = plygrnd.GetComponentInChildren<PlaygroundController>();
            //pgc.PlaygroundReset();
            plygrndCtrlers.Add(pgc);
            float playgroundGap = ((float)epm.GetPara(EP.boundaryRight)-(float)epm.GetPara(EP.boundaryLeft))*3;
            plygrndPosPointer += new Vector3(playgroundGap, 0, 0);
        }
        cameraController.player = plygrndCtrlers[0].flightAgents[0].airplane.gameObject;
    }

    public void SetDone(bool value)
    {
        isDone = value;
        sideChannelController.SendStateMessage();
    }

    public bool GetDone()
    {
        return isDone;
    }

    public void EnvironmentReset()
    {
        //2021.4.10 放弃hardset功能的实现
        if(isHardReset)
        {
            isHardReset = false;
            //Destroy object之后，在python端get_step()得到的信息是terminated的那几个agent
            //如果需要直接到达新生成的agent的request的时候，则需要再step()一下
            foreach (PlaygroundController pgc in plygrndCtrlers)
            {
                Destroy(pgc.transform.parent.gameObject);
            }
            Instantiate();
        }
        else if(isFirstReset)
        {
            isFirstReset = false;
            Instantiate();
            foreach (PlaygroundController pgc in plygrndCtrlers)
            {
                pgc.PlaygroundReset();
            }
        }
        else
        {
            doneAgentNum = 0;
            SetDone(false);
            foreach(PlaygroundController pgc in plygrndCtrlers)
            {
                pgc.PlaygroundReset();
            }
        }
    }

    void FixedUpdate()
    {
        Academy.Instance.EnvironmentStep();
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.R))
        {
            EnvironmentReset();
            //Debug.LogError("This is a fake error. Space bar was pressed in Unity.");
            //Debug.Log("The EnvPara targetPosX is:"+envCtrler.eps.GetWithDefault("targetPosX",0.123f).ToString());
            //Debug.Log("One Normal Distribution Sample:"+MathUtils.NormalDisSample(0.0f,1.0f).ToString());
            //Debug.Log("The EnvPara targetPosX is:"+envCtrler.epm.GetPara(EP.targetPosX).ToString());
        }
    }

}
